
package ija.xls.xml.config;

import ija.model.players.ComputerPlayer;
import ija.model.players.LocalPlayer;
import ija.model.players.Player;
import ija.model.players.RemotePlayer;
import ija.model.players.RemotePlayer.ConnectType;
import ija.model.types.FigureColor;
import ija.model.types.FigureDirection;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 *
 * @author Radek Necas, xnecas18
 */
public class PlayersReaderWriter {

    static public final String IMPLICIT_FILE = "./config/players.xml";

    
    protected Document doc;

    
    /**
     * Konstruktor vytvari instanci objektu s null polozkami.
     */
    public PlayersReaderWriter() {
        doc = null;
    }
    
    
    ////////////////////////////////////////////////////////////////////////////
    //-------------------------- READER ---------------------------------------
    ///////////////////////////////////////////////////////////////////////////
    
    
    /**
     * Metoda inicializuje objekt
     * @param filename cesta k souboru
     * @throws DocumentException 
     */
    public void init(String filename) throws DocumentException {
        SAXReader reader = new SAXReader();
        this.doc = reader.read(filename);
    }
    
    /**
     * Metoda inicializuje objekt. Pocita se s implicitnim souborem.
     * @throws DocumentException 
     */
    public void init() throws DocumentException {
        init(IMPLICIT_FILE);
    }
    
    /**
     * Metoda pro pruchod skrze vsechny posledni hrace
     * @return iterator skrze vsechny posledni hrace
     */
    public Iterator<Player> lastPlayersIterator() {
        return new LastPlayersIterator();
    }
    
    /**
     * Metoda pro pruchod skrze vsechny ulozene vzdalene hrace
     * @return iterator pres vsechny ulozene vzdalene hrace
     */
    public Iterator<Player> storePlayersIterator() {
        return new StorePlayersIterator();
    }
    
    
    ////////////////////////////////////////////////////////////////////////////
    //--------------------------- WRITER ---------------------------------------
    ////////////////////////////////////////////////////////////////////////////
    
    
    /**
     * Metoda ulozi posledni hraciji hrace
     * @param p0 hrac s id 0
     * @param p1 hrac s id 1
     */
    public void saveLastPlayers(Player p0, Player p1) {
        Node lastGame = doc.selectSingleNode("/IjaPlayers/lastGame");
        lastGame.detach();
        
        Element root = doc.getRootElement();
        Element lg = root.addElement("lastGame");
        Player p;
        
        for(int i = 0; i < 2; i++) {
            // Prirazeni spravneho hrace
            if(i == 0) {
                p = p0;
            }
            else {
                p = p1;
            }
            
            // Hodnoty spolecne vsem typum hracu
            Element player = lg.addElement("player").addAttribute("id", String.valueOf(i));
            player.addElement("name").addText(p.getName());
            player.addElement("color").addText(p.getColor().toString());
            player.addElement("direction").addText(p.getDirection().toString());
                
            // Hodnoty lokalniho hrace
            if(p instanceof LocalPlayer) {
                player.addAttribute("type", "local");
                
            }
            // Hodnoty vzdaleneho hrace
            else if(p instanceof RemotePlayer) {
                RemotePlayer pr = (RemotePlayer)p;
                player.addAttribute("type", "remote");
                player.addElement("address").addText(pr.getIp());
                player.addElement("port").addText(String.valueOf(pr.getPort()));
                player.addElement("connectType").addText(pr.getConnectType().toString());
            }
            // Hodnoty AI
            else if(p instanceof ComputerPlayer) {
                ComputerPlayer pc = (ComputerPlayer)p;
                player.addAttribute("type", "ai");
                player.addElement("level").addText(String.valueOf(pc.getLevel()));
            }
        }
    }
    
    /**
     * Metoda prida dalsiho vzdaleneho hrace.
     * Uklada se nazev, ip a port.
     * @param rp vzdaleny hrac, jenz se ma ulozit
     */
    public void addStorePlayer(RemotePlayer rp) {
        Element storePlayers = (Element) doc.selectSingleNode("/IjaPlayers/storePlayers");
        Element player = storePlayers.addElement("player");
        player.addElement("name").addText(rp.getName());
        player.addElement("address").addText(rp.getIp());
        player.addElement("port").addText(String.valueOf(rp.getPort()));
    }
    
    /**
     * Metoda zapise xml do souboru
     * @param filename nazev souboru (i s cestou)
     * @throws IOException 
     */
    public void writeToFile(String filename) throws IOException {
        if (this.doc == null) {
            this.doc = DocumentHelper.createDocument();
            Element root = this.doc.addElement("IjaPlayers");
        }
        
        OutputFormat format = OutputFormat.createPrettyPrint();
        XMLWriter writer = new XMLWriter(new FileWriter(filename), format);
        // XMLWriter writer = new XMLWriter(System.out, format);
        writer.write(this.doc);
        writer.flush();
        writer.close();
    }
    
    /**
     * Metoda zapise hrace do implicitniho souboru.
     * @throws IOException 
     */
    public void writeToFile() throws IOException {
        writeToFile(IMPLICIT_FILE);
    }
    
    
    
    //==========================================================================
    //--------------------- VNORENA TRIDA LASTPLAYERSITERATOR ------------------
    //==========================================================================
    
    
    /**
     * Iterator je zodpovedny za pruchod skrze vsechny posledne hrajici hrace.
     */
    public class LastPlayersIterator implements Iterator<Player> {
        Iterator it;
        
        public LastPlayersIterator() {
            Element root = PlayersReaderWriter.this.doc.getRootElement();
            //Element last = root.element("last");
            Element last = (Element) doc.selectSingleNode("/IjaPlayers/lastGame");
            this.it = last.elementIterator("player");
        }

        @Override
        public boolean hasNext() {
            return it.hasNext();
        }

        @Override
        public Player next() {
            Element e = (Element) this.it.next();
            // Ziskani atributu elementu
            String type = e.attributeValue("type");
            int id = Integer.parseInt(e.attributeValue("id"));
            // Naplneni hodnot konkretniho hrace
            String name = e.elementText("name");
            FigureColor color = FigureColor.getFromString(e.elementText("color"));
            FigureDirection direction = FigureDirection.getFromString(e.elementText("direction"));
            // Naplneni hodnot pro specificky typ hrace
            if (type.equals("local")) {
                    return new LocalPlayer(name, color, direction);
            } else if (type.equals("remote")) {
                    String ip = e.elementText("address");
                    int port = Integer.parseInt(e.elementText("port"));
                    RemotePlayer.ConnectType ct = RemotePlayer.ConnectType.getFromString(e
                                    .elementText("connectType"));
                    return new RemotePlayer(name, color, direction, ct, ip, port);
            } else if (type.equals("ai")) {
                    int level = Integer.parseInt(e.elementText("level"));
                    return new ComputerPlayer(name, color, direction, level);
            }

            return null;
            
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
    
    
    //==========================================================================
    //--------------------- VNORENA TRIDA STOREPLAYERSITERATOR -----------------
    //==========================================================================
    
    
    /**
     * Iterator je zodpovedny za pruchod skrze vsechny ulozene vzdalene hrace.
     * U techto hracu je ulozeno pouze jmeno, ip a port
     */
    public class StorePlayersIterator implements Iterator<Player> {

        Iterator it;
        
        public StorePlayersIterator() {
            Element root = PlayersReaderWriter.this.doc.getRootElement();
            //Element last = root.element("storePlayers");
            Element store = (Element) doc.selectSingleNode("/IjaPlayers/storePlayers");
            this.it = store.elementIterator("player");
        }

        @Override
        public boolean hasNext() {
            return this.it.hasNext();
        }

        @Override
        public Player next() {
            Element e = (Element) this.it.next();
            String name = e.elementText("name");
            String ip = e.elementText("address");
            int port = Integer.parseInt(e.elementText("port"));
            return new RemotePlayer(name, FigureColor.UNKNOWN, FigureDirection.NONE,
                    ConnectType.INITIATOR, ip, port);
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
}
